#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <chrono>
#include <atomic>
#include <condition_variable>
#include <random>

// 共享资源
struct SharedData {
    std::mutex mtx;          // 保护共享数据的互斥锁
    int counter = 0;         // 共享计数器
    double accumulator = 0.0;// 共享累加器
};

// 同步屏障实现
struct Barrier {
    std::mutex mtx;
    std::condition_variable cv;
    int count;
    int initial_count;
    int generation;

    Barrier(int count) : count(count), initial_count(count), generation(0) {}

    void arrive_and_wait() {
        std::unique_lock<std::mutex> lock(mtx);
        int current_generation = generation;
        
        if (--count == 0) {
            generation++;
            count = initial_count;
            cv.notify_all();
        } else {
            cv.wait(lock, [this, current_generation] {
                return current_generation != generation;
            });
        }
    }
};

// 配置参数
struct Config {
    int num_processes = 8;   // 进程数量
    int compute_iterations = 100000; // 每个进程内部计算循环次数
    int outer_iterations = 10;      // 外部循环次数
    bool run_single_thread = true;  // 是否运行单线程测试
};

long fact(int ip) {
  if (ip == 1) {
    return 1;
  }
  else {
    return ip * fact(ip - 1);
  }
}

int fibonacci(int index) {
  if (index == 1 || index == 2) {
    return 1;
  }
  return fibonacci(index - 1) + fibonacci(index - 2);
}

// 模拟CPU密集型计算
double cpu_intensive_computation(int iterations, int seed) {
    // 使用随机数生成器模拟不同的计算路径
    std::mt19937 rng(seed);
    std::uniform_real_distribution<double> dist(0.0001, 0.001);
    
    double result = 0.0;
    int n = 12;
    unsigned long long factorial = 1;
    int fibonacci_result = 0;
    for (int i = 0; i < iterations; ++i) {
        // 模拟一些计算工作
        result += std::sin(i * 0.001) * std::cos(i * 0.002);
        factorial = fact(n);
        fibonacci_result = fibonacci(12);
        // 随机添加一些延迟来模拟不同的计算负载
        if (i % 10000 == 0) {
            std::this_thread::sleep_for(std::chrono::duration<double>(dist(rng)));
        }
    }
    return result;
}

// 多线程工作函数
void process_worker(int process_id, int outer_loop,
                   const Config& config, 
                   SharedData& shared_data,
                   Barrier& sync_barrier) {
    
    // 1. 进行本地计算
    double local_result = cpu_intensive_computation(
        config.compute_iterations, 
        process_id * 1000 + outer_loop // 为每轮循环生成不同种子
    );
    
    // 2. 等待所有进程完成计算（同步点）
    sync_barrier.arrive_and_wait();
    
    // 3. 访问共享资源（需要加锁）
    {
        std::lock_guard<std::mutex> lock(shared_data.mtx);
        shared_data.counter++;
        shared_data.accumulator += local_result;
        
        // 仅在调试模式下输出详细信息，避免影响性能测量
        #ifdef DEBUG
        std::cout << "进程 " << process_id 
                  << " 完成第 " << outer_loop << " 轮计算" 
                  << " | 共享计数器: " << shared_data.counter 
                  << std::endl;
        #endif
    }
    
    // 4. 等待所有进程完成共享资源访问（同步点）
    sync_barrier.arrive_and_wait();
}

// 单线程执行所有工作
double run_single_thread(const Config& config) {
    SharedData shared_data;
    
    auto start_time = std::chrono::high_resolution_clock::now();
    
    for (int outer = 0; outer < config.outer_iterations; ++outer) {
        // 单线程依次执行所有"进程"的工作
        for (int i = 0; i < config.num_processes; ++i) {
            // 进行计算
            double local_result = cpu_intensive_computation(
                config.compute_iterations, 
                i * 1000 + outer
            );
            
            // 访问共享资源（单线程不需要锁，但保持相同操作）
            shared_data.counter++;
            shared_data.accumulator += local_result;
        }
    }
    
    auto end_time = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> total_time = end_time - start_time;
    
    #ifdef DEBUG
    std::cout << "单线程计算完成 | 总操作次数: " << shared_data.counter << std::endl;
    #endif
    
    return total_time.count();
}

// 多线程执行
double run_multi_thread(const Config& config) {
    SharedData shared_data;
    
    auto start_time = std::chrono::high_resolution_clock::now();
    
    // 外部循环 - 每轮都会重新创建进程
    for (int outer = 0; outer < config.outer_iterations; ++outer) {
        // 为当前轮次创建屏障
        Barrier sync_barrier(config.num_processes);
        
        // 创建并启动本轮的所有进程
        std::vector<std::thread> processes;
        for (int i = 0; i < config.num_processes; ++i) {
            processes.emplace_back(
                process_worker, 
                i, 
                outer,
                std::ref(config), 
                std::ref(shared_data),
                std::ref(sync_barrier)
            );
        }
        
        // 等待本轮所有进程完成并join
        for (auto& proc : processes) {
            proc.join();
        }
        
        #ifdef DEBUG
        std::cout << "第 " << outer << " 轮多线程计算完成" << std::endl;
        #endif
    }
    
    auto end_time = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> total_time = end_time - start_time;
    
    #ifdef DEBUG
    std::cout << "多线程计算完成 | 总操作次数: " << shared_data.counter << std::endl;
    #endif
    
    return total_time.count();
}

int main(int argc, char* argv[]) {
    Config config;
    
    // 可以通过命令行参数覆盖默认配置
    // 参数顺序: 进程数量 计算循环次数 外部循环次数 [是否运行单线程(0/1)]
    if (argc > 1) config.num_processes = std::stoi(argv[1]);
    if (argc > 2) config.compute_iterations = std::stoi(argv[2]);
    if (argc > 3) config.outer_iterations = std::stoi(argv[3]);
    if (argc > 4) config.run_single_thread = (std::stoi(argv[4]) != 0);
    
    std::cout << "===== 多进程CPU仿真器测试 =====" << std::endl;
    std::cout << "进程数量: " << config.num_processes << std::endl;
    std::cout << "每个进程计算循环次数: " << config.compute_iterations << std::endl;
    std::cout << "外部循环次数: " << config.outer_iterations << std::endl;
    std::cout << "是否运行单线程测试: " << (config.run_single_thread ? "是" : "否") << std::endl;
    std::cout << "==============================" << std::endl;
    
    double single_thread_time = 0.0;
    if (config.run_single_thread) {
        std::cout << "开始单线程测试..." << std::endl;
        single_thread_time = run_single_thread(config);
        std::cout << "单线程总耗时: " << single_thread_time << " 秒" << std::endl;
    }
    
    std::cout << "开始多线程测试..." << std::endl;
    double multi_thread_time = run_multi_thread(config);
    std::cout << "多线程总耗时: " << multi_thread_time << " 秒" << std::endl;
    
    // 计算加速比（如果运行了单线程测试）
    if (config.run_single_thread) {
        double speedup = single_thread_time / multi_thread_time;
        std::cout << "加速比: " << speedup << std::endl;
    }
    
    // 输出标准化结果，便于Python脚本解析
    std::cout << "===== 结果汇总 =====" << std::endl;
    std::cout << "单线程耗时: " << single_thread_time << std::endl;
    std::cout << "多线程耗时: " << multi_thread_time << std::endl;
    if (config.run_single_thread) {
        std::cout << "加速比: " << (single_thread_time / multi_thread_time) << std::endl;
    }
    
    return 0;
}
